CloudWatch Logs を文字列検知してログ内容をメールを送信してみた サブスクリプションフィルター版
こんにちは。
ご機嫌いかがでしょうか。
"No human labor is no human error" が大好きな吉井 亮です。
アプリケーションや OS のログファイルから特定の文字列をマッチし メール等で担当者へ通知する運用はクラウドにおいても必要です。
今回は CloudWatch Logs に出力しているログファイルから サブスクリプションを使用して特定文字列マッチを行い、SNS で通知する方法を試してみます。
Lambda 関数の Python コードを修正しました。
以前のコードですと複数回イベントが発生した際に初回イベントしか通知されないと問題がありました。
ループ処理を加えることより複数回のイベントを取得できるように修正しました。
以前のコードをご利用頂いている方は大変お手数ですがコード修正をお願いします。
構成
ログの流れは以下の通りです。
- EC2 等から CloudWatch Logs へログファイル出力
- サブスクリプションフィルターで特定文字列をマッチさせて Lambda 関数を起動
- Lambda 関数で該当メッセージを抽出、SNS 用に整形
- 該当文字列が含まれた行を SNS で通知(今回はメール)
実装
それでは実装していきます。
メール通知用 SNS トピックの作成
このトピックはメール通知で使います。 SNS トピック を開きます。 トピックの作成 をクリックします。
[トピックの作成] 画面で任意の名前と表示名を入力し、画面下部の トピックの作成 をクリックします。
次の画面で サブスクリプションの作成 をクリックします。
プロトコルを Eメール に、エンドポイントに ご自身のメールアドレス を入力し、画面下部の サブスクリプションの作成 をクリックします。
しばらくすると AWS Notification - Subscription Confirmation という件名のメールが来ると思います。
本文をよく確認して Confirm を行ってください。
Lambda 関数の作成
Lambda 関数 を開きます。
関数の作成 をクリックします。
一から作成 を選択します。
任意の関数名を入力します。
ランタイムを選択します。今回は Python 3.7 を選択します。
関数の作成をクリックします。
コード
コードは以下を貼り付けます。
import base64 import json import zlib import datetime import os import boto3 from botocore.exceptions import ClientError print('Loading function') def lambda_handler(event, context): data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS) data_json = json.loads(data) log_entire_json = json.loads(json.dumps(data_json["logEvents"], ensure_ascii=False)) log_entire_len = len(log_entire_json) print(log_entire_json) for i in range(log_entire_len): log_json = json.loads(json.dumps(data_json["logEvents"][i], ensure_ascii=False)) try: sns = boto3.client('sns') #SNS Publish publishResponse = sns.publish( TopicArn = os.environ['SNS_TOPIC_ARN'], Message = log_json['message'], Subject = os.environ['ALARM_SUBJECT'] ) except Exception as e: print(e)
環境変数
環境変数に以下を入力します。
キー | 値 |
---|---|
SNS_TOPIC_ARN | 前の手順で作成したメール通知用トピック ARN |
ALARM_SUBJECT | SNS で通知される際の件名 |
基本設定 -> タイムアウト
関数のタイムアウトを1分に設定します。
※仮に1分にしていますが実際の環境に合わせてチューニングしてください。
実行ロールにポリシーをアタッチ
アクセス権限 タブを開きます。
実行ロールという項目に IAM コンソールへのリンクが表示されています。
そちらをクリックします。
IAM ロールが表示されたら ポリシーをアタッチします をクリックします。
AmazonSNSFullAccess をアタッチします。
※手順を簡易化するために大きめの権限を付与しています。
※実際の運用では適切な権限設定をお願いします。
サブスクリプションフィルタの作成
マネジメントコンソールで CloudWatch Logs を開きます。
対象のロググループをクリックします。
アクション → Lambda サブスクリプションフィルターを作成 をクリックします。
次の画面で以下を入力します。
項目 | 値 |
---|---|
Lambda 関数 | 前の手順で作成した関数 |
ログの形式 | 出力されるログに合わせた形式を選択 |
サブスクリプションフィルターのパターン | 検出する文字列・パターンを入力 |
ストリーミングを開始 をクリックします。
テスト
CloudWatch Logs にテスト用のメッセージを送信してみます。
aws logs put-log-events --log-group-name your-log-group-name --log-stream-name your-log-stream-name --log-events timestamp=`date +%s%3N`,message="This is Error" --sequence-token your-sequence
SNS 経由でメールが届けば成功です。
まとめ
アプリケーションログからエラーを検出して通知するという手段は今でも有効です。
サブスクリプションフィルターだけでは柔軟性に欠けるといった場合は、Lambda 関数のなかでフィルタリングを行うことでカスタマイズが可能です。お試しください。
参考
以上、吉井 亮 がお届けしました。